package com.danbay.framework.protocol.command;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @author SJG
 */
public class CommandBuilder implements BeanPostProcessor {
    private Log logger = LogFactory.getLog(getClass());

    private Map<String, CommandAction> commands = new HashMap<>(20);

    private Set<String> baseRoutes = new HashSet<>();

    /**
     * 初始化命令action
     */
    private void initCommandAction(Object cmd, String route) {
        //取出所有command的action
        Method[] methods = cmd.getClass().getMethods();
        for (Method m : methods) {
            RequestMapping mapping = m.getAnnotation(RequestMapping.class);
            if (mapping != null && mapping.value().length > 0) {
                String uri = route + mapping.value()[0];
                //将多个连续的/替换为一个
                uri = uri.replaceAll("/+", "/");
                Type[] types = m.getGenericParameterTypes();
                if (types.length > 1) {
                    logger.error(m.getName() + "命令方法参数多于1个");
                    continue;
                }
                logger.debug("found command:" + uri);
                CommandAction action = new CommandAction(uri, cmd, m, types.length == 0 ? null : types[0]);
                //添加到基路径集合
                baseRoutes.add(route);
                RequestMethod[] requestMethods = mapping.method();
                //未指定请求类型
                if (requestMethods.length == 0) {
                    commands.put("get:" + uri, action);
                    commands.put("post:" + uri, action);
                    commands.put(uri, action);
                }

                //为每个请求类型存储命令对象
                for (RequestMethod rm : requestMethods) {
                    commands.put(rm.name().toLowerCase() + ":" + uri, action);
                }
            }
        }
    }

    /**
     * 取路由对应的命令对象
     *
     * @param route 路由、路径
     * @return 命令对象
     */
    public CommandAction getCommand(String route) {
        CommandAction action = commands.get(route);
        if (action == null && route != null && route.indexOf(":") > 0) {
            String[] uriParts = route.split(":");
            //从基路径组合中查找
            for (String baseRoute : baseRoutes) {
                route = uriParts[0] + ":" + baseRoute + uriParts[1];
                action = commands.get(route);
                if(action!=null){
                    return action;
                }
            }
        }
        return action;
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        Class clazz = o.getClass();
        if (clazz.getAnnotation(Controller.class) != null ||
                clazz.getAnnotation(RestController.class) != null) {
            RequestMapping requestMapping = o.getClass().getAnnotation(RequestMapping.class);
            String rootPath = "";
            if (requestMapping != null) {
                rootPath = requestMapping.value()[0];
            }
            initCommandAction(o, rootPath);
        }
        return o;
    }
}
